﻿#pragma once

#include "../box/box_network.hh"
#include "../http/http_base.hh"
#include "../util/box_std_allocator.hh"
#include <cstdint>
#include <list>
#include <memory>
#include <unordered_map>

namespace kratos {
namespace service {
class ServiceBox;
}
namespace config {
class BoxConfig;
}
} // namespace kratos

struct http_parser_settings;
struct http_parser;

namespace kratos {
namespace http {

class HttpCallImpl;
struct HttpData;

/**
 * HTTP实现类
 *
 * 实现了HTTP客户端和服务器
 */
class HttpBaseImpl : public HttpBase, public service::BoxNetwork {
  using HttpCallMap = std::unordered_map<
      std::string, std::shared_ptr<HttpCallImpl>, std::hash<std::string>,
      std::equal_to<std::string>,
      kratos::service::Allocator<
          std::pair<const std::string, std::shared_ptr<HttpCallImpl>>>>;
  struct HttpListener {
    RequestHandler handler;
    std::uint64_t user_data;
  };
  using ListenHandlerMap = std::unordered_map<
      std::string, HttpListener, std::hash<std::string>,
      std::equal_to<std::string>,
      kratos::service::Allocator<std::pair<const std::string, HttpListener>>>;
  /**
   * 正在进行的调用信息.
   */
  struct NonFinishCall {
    std::weak_ptr<HttpCallImpl> call; ///< 未完成的调用
    std::time_t dead_line{0};         ///< 超时时间戳
  };
  using NonFinishMap = std::unordered_map<
      std::string, NonFinishCall, std::hash<std::string>,
      std::equal_to<std::string>,
      kratos::service::Allocator<std::pair<const std::string, NonFinishCall>>>;
  /**
   * HTTP调用相关协程信息.
   */
  struct CoroHttpInfo {
    HttpCallPtr call;         ///< 协程调用
    std::uint64_t coro_id{0}; ///< 协程ID
  };
  using CoroListenerMap = std::unordered_map<
      std::string, CoroHttpInfo, std::hash<std::string>,
      std::equal_to<std::string>,
      kratos::service::Allocator<std::pair<const std::string, CoroHttpInfo>>>;
  /**
   * 监听器信息.
   */
  struct ListenerInfo {
    std::string host;          ///< 主机
    std::string listener_name; ///< 监听器名称
    int port{0};               ///< 监听的端口号
  };
  using ListenerList =
      std::list<ListenerInfo, kratos::service::Allocator<ListenerInfo>>;
  /**
   * 连接器信息.
   */
  struct ConnectorInfo {
    std::uint64_t coro_id{0}; ///< 协程ID
    std::time_t dead_line{0}; ///< 超时时间戳
  };
  using ConnectorMap = std::unordered_map<
      std::string, ConnectorInfo, std::hash<std::string>,
      std::equal_to<std::string>,
      kratos::service::Allocator<std::pair<const std::string, ConnectorInfo>>>;
  service::ServiceBox *box_{nullptr}; ///< 服务容器
  HttpCallMap call_map_;              ///< 调用表
  std::uint64_t name_index_{1};       ///< 名字自增索引
  ListenerList listener_list_;        ///< 监听器列表
  NonFinishMap
      non_finish_map_; ///< 未完成的调用, HTTP协议解析已经完成，但是调用未完成
  CoroListenerMap coro_listener_map_;   ///< 在协程内开启的监听器表
  ConnectorMap coro_connector_map_;     ///< 协程内启动的连接器
  ListenHandlerMap listen_handler_map_; ///< 监听器回调表

  constexpr static std::time_t DEFAULT_MAX_TIMEOUT =
      60; ///< HTTP调用默认超时，秒

public:
  /**
   * 构造
   *
   * \param box 服务容器
   */
  HttpBaseImpl(service::ServiceBox *box);
  /**
   * 析构
   */
  virtual ~HttpBaseImpl();
  virtual auto
  do_request_async(const std::string &host, int port, const std::string &uri,
                   const std::string &method, const HeaderMap &headers,
                   const std::string &content, int timeout,
                   std::uint64_t user_data, ResponseHandler handler)
      -> bool override;
  virtual auto do_request_co(const std::string &host, int port,
                             const std::string &uri, const std::string &method,
                             const HeaderMap &headers,
                             const std::string &content, int timeout)
      -> HttpCallPtr override;
  virtual auto wait_request_async(const std::string &host, int port,
                                  std::uint64_t user_data,
                                  RequestHandler handler) -> bool override;
  virtual auto wait_request_co(const std::string &host, int port)
      -> HttpCallPtr override;
  virtual auto update(std::time_t ms) -> void override;

public:
  virtual auto get_config() -> kratos::config::BoxConfig & override;
  virtual auto get_logger_appender() -> klogger::Appender * override;
  virtual auto get_lang() -> lang::Lang * override;
  virtual void
  on_listen(const std::string &name, bool success,
            std::shared_ptr<service::BoxChannel> &channel) override;
  virtual void
  on_accept(std::shared_ptr<service::BoxChannel> &channel) override;
  virtual void
  on_connect(const std::string &name, bool success,
             std::shared_ptr<service::BoxChannel> &channel) override;
  virtual void on_close(std::shared_ptr<service::BoxChannel> &channel) override;
  virtual void on_data(std::shared_ptr<service::BoxChannel> &channel) override;

private:
  //// 以下函数为http_parser_settings的回调函数，具体含义参见@see http_parser

  static int on_message_begin(http_parser *);
  static int on_message_complete(http_parser *);
  static int on_url(http_parser *, const char *at, std::size_t length);
  static int on_header_field(http_parser *, const char *at, std::size_t length);
  static int on_header_value(http_parser *, const char *at, std::size_t length);
  static int on_status(http_parser *, const char *at, std::size_t length);
  static int on_headers_complete(http_parser *);
  static int on_body(http_parser *, const char *at, std::size_t length);
  static int on_chunk_header(http_parser *);
  static int on_chunk_complete(http_parser *);

private:
  /**
   * 产生一个新的客户端名称，不重复.
   *
   * \return 客户端名称
   */
  auto gen_client_name() -> std::string;
  /**
   * 产生一个新的连接器名称，不重复.
   *
   * \return 客户端名称
   */
  auto gen_connector_name() -> std::string;
  /**
   * 获取HTTP调用表.
   *
   * \return HTTP调用表
   */
  auto get_call_map() -> HttpCallMap &;
  /**
   * 获取监听器处理器表.
   *
   * \return 监听器处理器表
   */
  auto get_listener_map() -> ListenHandlerMap &;
  /**
   * 获取未完成的调用表, HTTP协议解析已经完成，但是调用未完成.
   *
   * \return 未完成的调用表
   */
  auto get_non_finish_map() -> NonFinishMap &;
  /**
   * 清理所有超时的未完成调用.
   *
   * \param ms 当前时间戳，毫秒
   * \return
   */
  auto clean_timeout_call(std::time_t ms) -> void;
  /**
   * 获取在协程内启动的监听器表.
   *
   * \return 在协程内启动的监听器表
   */
  auto get_coro_listener_map() -> CoroListenerMap &;
  /**
   * 判断监听器是否存在.
   *
   * \param host 监听地址
   * \param port 监听端口
   * \return true或false
   */
  auto is_listener_exists(const std::string &host, int port) -> bool;
  /**
   * 获取监听器名字.
   *
   * \param host 监听地址
   * \param port 监听端口
   * \return 监听器名字
   */
  auto get_listener_name(const std::string &host, int port)
      -> const std::string &;
  /**
   * 写日志.
   *
   * \param level 日志等级
   * \param log_line 日志行
   * \return
   */
  auto write_log_line(int level, const std::string &log_line) -> void;
  /**
   * 添加协程连接器信息.
   *
   * \param name 连接器名称
   * \param info 连接器信息
   * \return
   */
  auto add_connector_co(const std::string &name, const ConnectorInfo &info)
      -> void;
  /**
   * 删除协程连接器.
   *
   * \param name 连接器名称
   * \return
   */
  auto remove_connector_co(const std::string &name) -> void;
  /**
   * 检查未连接成功的协程连接器.
   *
   * \param ms 当前时间戳，毫秒
   * \return
   */
  auto check_non_finish_connector_co(std::time_t ms) -> void;
  /**
   * 获得HTTP调用最大超时时间，秒.
   *
   * \return HTTP调用最大超时时间，秒
   */
  auto get_http_max_call_timeout() -> std::time_t;
};

} // namespace http
} // namespace kratos
